import std.stdio;
import std.traits;

alias Helper(alias T) = T;

alias FUN = void delegate(int);

FUN[string]  getList(T)(T a)
{
    FUN[string] functions;
    foreach(memberName; __traits(derivedMembers, T))
    {
        alias TFUN = Helper!(__traits(getMember,  a, memberName));
        static if (is(typeof(TFUN) == function) )
        {
                // I honestly don't really understand how this argument stuff works
            foreach (t;__traits(getOverloads,T,memberName)) 
            {
                Parameters!(t) functionArguments;
                static if(functionArguments.length == 1 &&  is(typeof(functionArguments[0]) == int) ){
                    FUN ft = &(__traits(getMember,  a, memberName));
                    functions[memberName] = ft;
                }
            }
        }
    }
    return functions;
}

string  getListStr(T)()
{
    string str = "override bool doFun(string funName,int i,int b = 0) {";
    str ~= "switch(funName){";
    foreach(memberName; __traits(allMembers, T))
    {
        static if (is(typeof(__traits(getMember,  T, memberName)) == function) )
        {
            foreach (t;__traits(getOverloads,T,memberName)) 
            {
                Parameters!(t) functionArguments;
                static if(functionArguments.length == 2 && is(typeof(functionArguments[0]) == int) && is(typeof(functionArguments[1]) == int))
                {
                    str ~= "case \"";
                    str ~= memberName;
                    str ~= "\":";
                    str = str ~  memberName ~ "(i,b); return true;";
                }
            }
        }
    }
    str ~= "default : return false;}";
    str ~= "}";
    return str;
}

template BuildFun(T)
{
    enum BuildFun = getListStr!T();
}

mixin template BuildFunT()
{
    mixin(BuildFun!(typeof(this)));
}

interface IMay
{
    bool doFun(string funName,int i, int b = 0);
}

class May : IMay
{
    void show(int i)
    {
        writeln("show " ,i);
    }
    
    void show2(int i)
    {
        writeln("show2 " ,i);
    }
    
    void show2(int i, int b)
    {
        writeln("show2 i = " ,i, "  b = ", b);
    }
    
    void show3(int i, int b)
    {
        writeln("show3 i = " ,i, "  b = ", b);
    }
    
    mixin(BuildFun!May);
    
    this()
    {
        functions = getList!(typeof(this))(this); //这种方法
    }

    
    FUN[string] functions;
}

class May2 :May
{
    override void show3(int i, int b)
    {
        writeln("May2 i = " ,i, "  b = ", b);
    }
    
    //mixin(BuildFun!May2);
    mixin BuildFunT;
}

void main()
{
    enum str = BuildFun!May;
    writeln("str is  :  ", str);
    
    writeln("May devideMen : ",__traits(derivedMembers, May));
    writeln("May AllMen : ",__traits(allMembers, May));

    May a = new May;
    
    auto dt = a.functions.get("show",null);
    if(dt) dt(5);
    dt = a.functions.get("show2",null);
    if(dt) dt(5*2);
    
    dt = a.functions.get("show3",null);
    if(dt) dt(5*3);
    
 /*   foreach(key,val;a.functions)
    {
        val(5);
    } */
    
   writeln(" The show3 value :" ,a.doFun("show3", 400,0));
    writeln(" The show2 value :" ,a.doFun("show2", 8000,0));
    writeln(" The show8 value :" ,a.doFun("show8", 8000,0));
    writeln(" The show value :" ,a.doFun("show", 8000,0));
    
    May2 ny2 = new May2();
    writeln(" The sMay how3 value :" ,ny2.doFun("show3", 400,0));
    writeln(" The show2 value :" , ny2.doFun("show2", 500,0));
    writeln(" The show : ", ny2.doFun("show", 1));
    
    
    writeln("MAY 2 str is  :  ", BuildFun!May2);
 //   writeln();
}
